/**
 * AjLog - The AspectJ based logging facade
 * 
 * Copyright (C) 2009 - 2010, Marko Umek. All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.ajlog.util;

import java.util.Date;
import java.util.Formatter;

/**
 * Logger is AjLogs internal logger.
 * 
 * @author Marko Umek
 * 
 */
public class AjLogLogger {
    private final String         classname;
    private final boolean        enabled;
    private static final boolean ajLogDebug;

    static {
        if (System.getProperties().containsKey("ajlog.debug")) {
            ajLogDebug = true;
        }
        else {
            ajLogDebug = false;
        }
    }

    public static AjLogLogger getLogger(final Class<?> clazz, final boolean enabled) {
        return new AjLogLogger(clazz, enabled);
    }

    public static AjLogLogger getLogger(final Class<?> clazz) {
        return new AjLogLogger(clazz, ajLogDebug);
    }

    private AjLogLogger(final Class<?> clazz, final boolean enabled) {
        this.classname = clazz.getSimpleName();
        this.enabled = enabled;
    }

    /**
     * Print a internal debug message to console using System.out
     * 
     * @param format
     *            see {@link Formatter}
     * @param args
     *            the arguments
     */
    public void debug(final String format, final Object... args) {
        this.infoMessage("DEBUG", format, args);
    }

    /**
     * Print a internal INFO message to console using System.out
     * 
     * @param format
     *            see {@link Formatter}
     * @param args
     *            the arguments
     */
    public void info(final String format, final Object... args) {
        this.infoMessage("INFO", format, args);
    }

    /**
     * Print a internal WARNING message to console using System.out
     * 
     * @param format
     *            see {@link Formatter}
     * @param args
     *            the arguments
     */
    public void warn(final String format, final Object... args) {
        this.infoMessage("WARNING", format, args);
    }

    /**
     * Print a internal ERROR message to console using System.err
     * 
     * @param format
     *            see {@link Formatter}
     * @param args
     *            the arguments
     */
    public void error(final String format, final Object... args) {
        this.errorMessage("ERROR", format, args);
    }

    /**
     * Print a internal FATAL message to console using System.err
     * 
     * @param format
     *            see {@link Formatter}
     * @param args
     *            the arguments
     */
    public void fatal(final String format, final Object... args) {
        this.errorMessage("FATAL", format, args);
    }

    /**
     * Prepare the message and print to {@link System#err}
     * 
     * @param format
     * @param args
     */
    private void errorMessage(final String level, final String format, final Object[] args) {
        if (this.enabled) {
            final String message = this.prepare(level, format, args);
            System.err.println(message);
            this.printLastException(args);
        }
    }

    /**
     * Prepare the message and print to {@link System#out}
     * 
     * @param format
     * @param args
     */
    private void infoMessage(final String level, final String format, final Object[] args) {
        if (this.enabled) {
            final String message = this.prepare(level, format, args);
            System.out.println(message);
            this.printLastException(args);
        }
    }

    /**
     * prepare prepares the message
     * 
     * @param level
     * @param format
     * @param args
     * @return
     */
    private String prepare(final String level, final String format, final Object[] args) {
        final StringBuilder stringBuilder = new StringBuilder();
        final Formatter formatter = new Formatter(stringBuilder);

        formatter.format("AjLog - (%4$s) - %1$s - %2$tF %2$tT.%2$tL -  [%3$s] - ", level, new Date(), Thread.currentThread()
                .getName(), this.classname);
        formatter.format(format, args);

        return stringBuilder.toString();
    }

    private void printLastException(final Object[] args) {
        Throwable ex = null;
        for (int i = args.length - 1; i >= 0; i--) {
            if (args[i] instanceof Throwable) {
                ex = (Throwable) args[i];
                break;
            }
        }

        if (ex != null) {
            ex.printStackTrace();
        }

    }
}
